#ifndef __MY_DATA__
#define __MY_DATA__

#include "config.hpp"
#include <unordered_map>
#include <pthread.h>

namespace cloud
{
    struct BackupInfo
    {
        bool pack_flag;        // 压缩文件的标志位
        size_t fsize;          // 文件大小
        time_t mtime;          // 文件最后一次修改时间
        time_t atime;          // 文件最后一次访问时间
        std::string real_path; // 文件的实际存储路径
        std::string pack_path; // 文件压缩包存放路径
        std::string url;       // URL中的资源路径path

        // 初始化信息
        bool NewBackupInfo(const std::string &realpath)
        {
            FileUtil fu(realpath);
            if (fu.Exists() == false)
            {
                std::cout << "new backupbnfo : file is not exists!\n";
                return false;
            }

            Config *config = Config::GetInstance();
            // 获取文件信息
            std::string packdir = config->GetPackDir();
            std::string packsuffix = config->GetPackFileSuffix();      // 获取压缩文件后缀
            std::string download_prefix = config->GetDownloadPrefix(); // 文件下载路径

            pack_flag = false; // 开始不为压缩文件
            fsize = fu.FileSize();
            mtime = fu.LastMTime();
            atime = fu.LastATime();
            real_path = realpath; // 文件所在路径
            //./backdir/a.txt -> ./packdir/a.txt.lz
            pack_path = packdir + fu.FileName() + packsuffix; // 压缩包路径
            //./backdir/a.txt -> /download/a.txt
            url = download_prefix + fu.FileName(); // 文件下载路径

            return true;
        }
    };

    class DataManager
    {
    public:
        DataManager()
        {
            // 初始化读写锁
            pthread_rwlock_init(&_rwlock, nullptr);
            // 将拷贝文件的信息进行初始化
            _backup_file = Config::GetInstance()->GetBackupFile();
            // 初始化加载
            InitLoad();
        }

        ~DataManager()
        {
            // 销毁读写锁
            pthread_rwlock_destroy(&_rwlock);
        }
        // 插入数据信息
        bool Insert(const BackupInfo &info)
        {
            pthread_rwlock_wrlock(&_rwlock); // 上锁
            _table[info.url] = info;         // 数据不存在直接进行插入
            pthread_rwlock_unlock(&_rwlock); // 解锁

            // 数据持久化
            Storage();
            return true;
        }
        // 更新数据信息
        bool UpDate(const BackupInfo &info)
        {
            pthread_rwlock_wrlock(&_rwlock); // 上锁
            _table[info.url] = info;         // 数据不存在直接进行插入，否则更新对应的内容
            pthread_rwlock_unlock(&_rwlock); // 解锁

            // 数据持久化
            Storage();
            return true;
        }
        // 通过URL的文件资源路径，获取对应的备份文件的数据信息
        bool GetOneByUrl(const std::string &url, BackupInfo *info)
        {
            pthread_rwlock_wrlock(&_rwlock); // 上锁

            auto it = _table.find(url);
            if (it == _table.end())
            {
                // 没有找到
                pthread_rwlock_unlock(&_rwlock); // 解锁
                return false;
            }

            // 找到了
            *info = it->second;              // 迭代器的second就是val值
            pthread_rwlock_unlock(&_rwlock); // 解锁

            return true;
        }
        // 通过文件路径查找备份文件的数据信息
        bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
        {
            pthread_rwlock_wrlock(&_rwlock); // 上锁

            // 遍历整个_table
            auto it = _table.begin();
            while (it != _table.end())
            {
                if (it->second.real_path == realpath)
                {
                    // 文件数据信息匹配到了
                    *info = it->second;
                    pthread_rwlock_unlock(&_rwlock); // 解锁
                    return true;
                }
                ++it;
            }

            // 没有找到
            pthread_rwlock_unlock(&_rwlock); // 解锁
            return false;
        }
        // 获取整个数据信息
        bool GetAll(std::vector<BackupInfo> *array) // 输出型参数
        {
            pthread_rwlock_wrlock(&_rwlock); // 上锁

            // 遍历整个_table
            auto it = _table.begin();
            while (it != _table.end())
            {
                //_table表中的val值都插入array中
                array->push_back(it->second);
                ++it;
            }
            pthread_rwlock_unlock(&_rwlock); // 解锁
            return true;
        }

        // 数据持久化操作
        bool Storage()
        {
            // 1.获取所有的数据信息
            std::vector<BackupInfo> array;
            GetAll(&array);
            // 2.将获取的数据添加到Json::Value对象
            Json::Value root;
            for (int i = 0; i < array.size(); i++)
            {
                Json::Value tmp;
                tmp["pack_flag"] = array[i].pack_flag;
                // Json不认识 time_t、size_t类型，需要强制类型转换
                tmp["fsize"] = (Json::Int64)array[i].fsize;
                tmp["mtime"] = (Json::Int64)array[i].mtime;
                tmp["atime"] = (Json::Int64)array[i].atime;
                tmp["real_path"] = array[i].real_path;
                tmp["pack_path"] = array[i].pack_path;
                tmp["url"] = array[i].url;
                // 整个数据不仅仅只有一份
                root.append(tmp);
            }
            // 3.序列化操作
            std::string body;
            JsonUtil::Serialize(root, &body);
            // 4.将数据存储到文件
            FileUtil fu(_backup_file); // 写入到备份文件
            fu.SetContent(body);
            return true;
        }

        // 数据初始化加载
        bool InitLoad()
        {
            // 1.将数据从文件中读取出来
            FileUtil fu(_backup_file);
            if (fu.Exists() == false)
            {
                // 文件不存在
                return true;
            }
            std::string body;
            //提取文件内容
            fu.GetContent(&body);

            // 2.反序列化
            Json::Value root;
            JsonUtil::UnSerialize(body, &root);

            // 3.将反序列化的数据添加到_table
            for (int i = 0; i < root.size(); i++)
            {
                BackupInfo info;
                info.pack_flag = root[i]["pack_flag"].asBool();

                info.fsize = root[i]["fsize"].asInt();
                info.mtime = root[i]["mtime"].asInt64();
                info.atime = root[i]["atime"].asInt64();

                info.pack_path = root[i]["pack_path"].asString();
                info.real_path = root[i]["real_path"].asString();
                info.url = root[i]["url"].asString();

                // 将info添加到_table中
                Insert(info);
            }
            return true;
        }

    private:
        pthread_rwlock_t _rwlock;                           // 读写锁
        std::string _backup_file;                           // 备份文件
        std::unordered_map<std::string, BackupInfo> _table; // 文件路径，数据信息对象
    };
}

#endif